package com.ikingtech.platform.business.message.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.enums.message.MessageChannelStatusEnum;
import com.ikingtech.framework.sdk.message.model.MessageTemplateQueryParamDTO;
import com.ikingtech.framework.sdk.message.model.rpc.MessageTemplateBeanDefinition;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.business.message.entity.*;
import com.ikingtech.platform.business.message.entity.*;
import com.ikingtech.platform.business.message.mapper.MessageTemplateMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author tie yan
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageTemplateService extends ServiceImpl<MessageTemplateMapper, MessageTemplateDO> {

    private final MessageParamDefinitionService paramDefinitionService;

    private final MessageReceiverDefinitionService receiverDefinitionService;

    private final MessageRedirectDefinitionService redirectDefinitionService;

    private final MessageChannelDefinitionService channelDefinitionService;

    public PageResult<MessageTemplateDO> listPage(MessageTemplateQueryParamDTO queryParam, List<String> ids) {
        return PageResult.build(this.page(new Page<>(queryParam.getPage(), queryParam.getRows()), Wrappers.<MessageTemplateDO>lambdaQuery()
                .eq(MessageTemplateDO::getConfigured, true)
                .like(Tools.Str.isNotBlank(queryParam.getBusinessKey()), MessageTemplateDO::getBusinessKey, queryParam.getBusinessKey())
                .eq(Tools.Str.isNotBlank(queryParam.getMessageTemplateKey()), MessageTemplateDO::getMessageTemplateKey, queryParam.getMessageTemplateKey())
                .like(Tools.Str.isNotBlank(queryParam.getMessageTemplateTitle()), MessageTemplateDO::getMessageTemplateTitle, queryParam.getMessageTemplateTitle())
                .in(Tools.Coll.isNotBlank(ids), MessageTemplateDO::getId, ids)));
    }

    /**
     * 消息模板定义信息上报
     *
     * @param beanDefinitions 消息模板定义信息集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void report(List<MessageTemplateBeanDefinition> beanDefinitions) {
        List<MessageTemplateDO> existEntities = this.list(Wrappers.<MessageTemplateDO>lambdaQuery().in(MessageTemplateDO::getMessageTemplateKey, Tools.Coll.convertList(beanDefinitions, MessageTemplateBeanDefinition::getMessageTemplateKey)));
        Map<String, MessageTemplateDO> existEntityMap = Tools.Coll.convertMap(existEntities, MessageTemplateDO::getMessageTemplateKey);

        List<MessageTemplateDO> newEntities = new ArrayList<>();
        List<MessageTemplateDO> updateEntities = new ArrayList<>();
        List<MessageChannelDefinitionDO> channelDefinitionEntities = new ArrayList<>();
        List<MessageParamDefinitionDO> paramDefinitionEntities = new ArrayList<>();
        List<MessageReceiverDefinitionDO> receiverDefinitionEntities = new ArrayList<>();
        List<MessageRedirectDefinitionDO> redirectDefinitionEntities = new ArrayList<>();
        beanDefinitions.forEach(beanDefinition -> {
            MessageTemplateDO templateEntity;

            String messageTemplateId;
            if (!existEntityMap.containsKey(beanDefinition.getMessageTemplateKey())) {
                templateEntity = Tools.Bean.copy(beanDefinition, MessageTemplateDO.class);
                messageTemplateId = Tools.Id.uuid();
                templateEntity.setId(messageTemplateId);
                newEntities.add(templateEntity);
            } else {
                templateEntity = existEntityMap.get(beanDefinition.getMessageTemplateKey());
                messageTemplateId = templateEntity.getId();
                templateEntity.setBusinessName(beanDefinition.getBusinessName());
                templateEntity.setBusinessKey(beanDefinition.getBusinessKey());
                templateEntity.setMessageTemplateTitle(beanDefinition.getMessageTemplateTitle());
                updateEntities.add(templateEntity);
                existEntityMap.remove(beanDefinition.getMessageTemplateKey());
            }
            templateEntity.setConfigured(false);
            templateEntity.setConfigurable(true);

            List<String> channelDefinitionIds = new ArrayList<>();
            if (Boolean.TRUE.equals(beanDefinition.getInternal()) &&
                    Tools.Coll.isNotBlank(beanDefinition.getChannelDefinitions())) {
                templateEntity.setConfigured(true);
                templateEntity.setConfigurable(false);
                channelDefinitionEntities.addAll(Tools.Coll.convertList(beanDefinition.getChannelDefinitions(), channel -> {
                    MessageChannelDefinitionDO entity = new MessageChannelDefinitionDO();
                    entity.setId(Tools.Id.uuid());
                    entity.setTemplateId(messageTemplateId);
                    entity.setChannel(channel.getChannel().name());
                    entity.setChannelId(channel.getChannelId());
                    entity.setChannelTemplateId(channel.getChannelTemplateId());
                    entity.setChannelDescription(channel.getChannelName());
                    entity.setContent(beanDefinition.getTemplateContent());
                    entity.setStatus(MessageChannelStatusEnum.ENABLED.name());
                    entity.setShowNotification(channel.getShowNotification());
                    entity.setSortOrder(1);
                    channelDefinitionIds.add(entity.getId());

                    // 处理消息跳转配置
                    if (Tools.Coll.isNotBlank(channel.getRedirectDefinitions())) {
                        redirectDefinitionEntities.addAll(Tools.Coll.convertList(channel.getRedirectDefinitions(), redirectDefinition -> {
                            MessageRedirectDefinitionDO redirectDefinitionEntity = Tools.Bean.copy(redirectDefinition, MessageRedirectDefinitionDO.class);
                            redirectDefinitionEntity.setId(Tools.Id.uuid());
                            redirectDefinitionEntity.setTemplateId(messageTemplateId);
                            if (Boolean.TRUE.equals(beanDefinition.getInternal())) {
                                redirectDefinitionEntity.setChannelDefinitionId(entity.getId());
                            }
                            return redirectDefinitionEntity;
                        }));
                    }
                    return entity;
                }));
            }

            // 处理消息模板参数
            if (Tools.Coll.isNotBlank(beanDefinition.getParamDefinitions())) {
                paramDefinitionEntities.addAll(Tools.Coll.convertList(beanDefinition.getParamDefinitions(), paramDefinition -> {
                    MessageParamDefinitionDO entity = Tools.Bean.copy(paramDefinition, MessageParamDefinitionDO.class);
                    entity.setId(Tools.Id.uuid());
                    entity.setTenantCode(Me.tenantCode());
                    entity.setTemplateId(messageTemplateId);
                    entity.setPreDefinition(true);
                    return entity;
                }));
                if (Boolean.TRUE.equals(beanDefinition.getInternal())) {
                    channelDefinitionIds.forEach(channelDefinitionId -> paramDefinitionEntities.addAll(Tools.Coll.convertList(beanDefinition.getParamDefinitions(), paramDefinition -> {
                        MessageParamDefinitionDO entity = Tools.Bean.copy(paramDefinition, MessageParamDefinitionDO.class);
                        entity.setId(Tools.Id.uuid());
                        entity.setTenantCode(Me.tenantCode());
                        entity.setTemplateId(messageTemplateId);
                        entity.setChannelDefinitionId(channelDefinitionId);
                        entity.setPreDefinition(false);
                        return entity;
                    })));
                }
            }

            // 处理消息接收者
            if (Tools.Coll.isNotBlank(beanDefinition.getReceiverDefinitions())) {
                receiverDefinitionEntities.addAll(Tools.Coll.convertList(beanDefinition.getReceiverDefinitions(), receiverDefinition -> {
                    MessageReceiverDefinitionDO entity = Tools.Bean.copy(receiverDefinition, MessageReceiverDefinitionDO.class);
                    entity.setId(Tools.Id.uuid());
                    entity.setTemplateId(messageTemplateId);
                    return entity;
                }));
            }
        });
        if (Tools.Coll.isNotBlank(newEntities)) {
            this.saveBatch(newEntities);
        }
        if (Tools.Coll.isNotBlank(updateEntities)) {
            this.updateBatchById(updateEntities);
        }
        List<String> deleteTemplateIds = Tools.Coll.convertList(new ArrayList<>(existEntityMap.values()), MessageTemplateDO::getId);
        if (Tools.Coll.isNotBlank(deleteTemplateIds)) {
            this.removeBatchByIds(deleteTemplateIds);
            this.channelDefinitionService.removeByTemplateIds(deleteTemplateIds);
            this.paramDefinitionService.removeByTemplateIds(deleteTemplateIds);
            this.receiverDefinitionService.removeByTemplateIds(deleteTemplateIds);
            this.redirectDefinitionService.removeByTemplateIds(deleteTemplateIds);
        }

        if (Tools.Coll.isNotBlank(channelDefinitionEntities)) {
            List<String> templateIds = Tools.Coll.convertList(channelDefinitionEntities, MessageChannelDefinitionDO::getTemplateId);
            this.channelDefinitionService.removeByTemplateIds(templateIds);
            this.channelDefinitionService.saveBatch(channelDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(paramDefinitionEntities)) {
            List<String> templateIds = Tools.Coll.convertList(paramDefinitionEntities, MessageParamDefinitionDO::getTemplateId);
            this.paramDefinitionService.removePreDefinitionByTemplateIds(templateIds);
            List<String> internalTemplateIds = Tools.Coll.convertList(newEntities, entity -> !Boolean.TRUE.equals(entity.getConfigurable()), MessageTemplateDO::getId);
            internalTemplateIds.addAll(Tools.Coll.convertList(updateEntities, entity -> !Boolean.TRUE.equals(entity.getConfigurable()), MessageTemplateDO::getId));
            if (Tools.Coll.isNotBlank(internalTemplateIds)) {
                this.paramDefinitionService.removeSettledDefinitionByTemplateIds(internalTemplateIds);
            }
            this.paramDefinitionService.saveBatch(paramDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(receiverDefinitionEntities)) {
            List<String> templateIds = Tools.Coll.convertList(receiverDefinitionEntities, MessageReceiverDefinitionDO::getTemplateId);
            this.receiverDefinitionService.removeByTemplateIds(templateIds);
            this.receiverDefinitionService.saveBatch(receiverDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(redirectDefinitionEntities)) {
            List<String> templateIds = Tools.Coll.convertList(redirectDefinitionEntities, MessageRedirectDefinitionDO::getTemplateId);
            this.redirectDefinitionService.removeByTemplateIds(templateIds);
            this.redirectDefinitionService.saveBatch(redirectDefinitionEntities);
        }
    }

    public MessageTemplateDO getByIdAndTenantCode(String id, String tenantCode) {
        return this.getOne(Wrappers.<MessageTemplateDO>lambdaQuery().eq(MessageTemplateDO::getId, id).eq(MessageTemplateDO::getTenantCode, tenantCode));
    }

    public MessageTemplateDO getByMessageTemplateKey(String messageTemplateKey) {
        return this.getOne(Wrappers.<MessageTemplateDO>lambdaQuery().eq(MessageTemplateDO::getMessageTemplateKey, messageTemplateKey));
    }

    public List<MessageTemplateDO> listBusinessKeyAndBusinessName(String businessName) {
        return this.list(Wrappers.<MessageTemplateDO>lambdaQuery()
                .like(Tools.Str.isNotBlank(businessName), MessageTemplateDO::getBusinessName, businessName));
    }

    public List<MessageTemplateDO> listNonConfiguredByBusinessKey(String businessKey) {
        return this.list(Wrappers.<MessageTemplateDO>lambdaQuery()
                .eq(MessageTemplateDO::getBusinessKey, businessKey)
                .eq(MessageTemplateDO::getConfigured, false));
    }

    public boolean exist(String id) {
        return this.baseMapper.exists(Wrappers.<MessageTemplateDO>lambdaQuery().eq(MessageTemplateDO::getId, id));
    }
}
